/**
    @brief Module affichage avec gtk, fichier source

    @file gtkview.cpp
    @version 0.1
    @date 2008/11/01

*/
#include <string>

#include "gtkview.h"
#include "txtview.h"
#include "../serializer/serializer.h"

GtkView::GtkView(int & argc, char **& argv, Session* newsession)
{

    /* Chargement de l'interface en mémoire */
    refXml = Gnome::Glade::Xml::create("emissary.glade");

    /* On récupère un pointeur sur les fenetres */
    refXml->get_widget("mainWin", mainWin); // La fenetre principale
    refXml->get_widget("dialog_Login", dialog_Login); // La fenetre de connexion initiale
    refXml->get_widget("dialog_JoinGroup", dialog_JoinGroup); // La fenetre pour rejoindre un groupe
    refXml->get_widget("dialog_AddMember", dialog_AddMember); // La fenetre pour rajouter un nouveau membre au groupe
    refXml->get_widget("dialog_About", dialog_About); // La fenetre about
    refXml->get_widget("dialog_FileChooser", dialog_FileChooser); // La fenetre qui permet de choisir les dossiers a indexer
    refXml->get_widget("dialog_NewGroup", dialog_NewGroup); // La fenetre pour créer un nouveau groupe

    // On lance la fenetre de connexion:
    infobus = newsession;

    int loginstatus;
    loginstatus = login(argc, argv);

    if (loginstatus == Gtk::RESPONSE_OK)
    {
    /* Initialisation du treeview */
    // récupérer un pointeur sur le widget TreeView
    refXml->get_widget("filetreeView", mTreeView);
    // creer le model (voir classe ModelColumns)
    mRefTreeModel = Gtk::TreeStore::create(mColumns);
    mTreeView->set_model(mRefTreeModel);
    // ajouter les colonnes
    mTreeView->append_column("Type", mColumns.icon_col);
    mTreeView->append_column("Name", mColumns.name_col);

    /* Notebook setup and initialisation */
    /* Initialise the iconview */
    refXml->get_widget("iconview_MainWin", mIconView);
    mRefListModel = Gtk::ListStore::create(mColumns);
    mIconView->set_model(mRefListModel);
    mIconView->set_markup_column(mColumns.name_col);
    mIconView->set_pixbuf_column(mColumns.icon_col);

    /* Initialise the labels */
    refXml->get_widget("entry_MainWinFileInfoName", entry_MainWinFileInfoName);
    refXml->get_widget("entry_MainWinFileInfoOwner", entry_MainWinFileInfoOwner);
    refXml->get_widget("entry_MainWinFileInfoType", entry_MainWinFileInfoType);

    fillTreeView();

    /* get the TreeSelection object from mTreeView*/
    refTreeSelection = mTreeView->get_selection();

    // This is where we connect the slot to the Glib::signal_timeout()
    sigc::connection conn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &GtkView::on_timeout), 1000);

    /* Initialise the main menu's buttons */
    /* Initialise the file menu's buttons */
    Gtk::ImageMenuItem* menu_AddFolder;
    Gtk::ImageMenuItem* menu_NewGroup;
    Gtk::ImageMenuItem* menu_JoinGroup;
    Gtk::ImageMenuItem* menu_Quit;

    /* Initialise the tool menu's buttons */
    Gtk::ImageMenuItem* menu_SyncFiles;
    Gtk::ImageMenuItem* menu_SyncContacts;


    /* Initialise the help menu's buttons */
    Gtk::ImageMenuItem* menu_About;


    /* Connect main menu's callback signals */
    /* File menu's callbacks */
    refXml->get_widget("menu_AddFolder", menu_AddFolder);
    menu_AddFolder->signal_activate().connect(sigc::mem_fun(*this, &GtkView::on_click_add) );

    refXml->get_widget("menu_NewGroup", menu_NewGroup);
    menu_NewGroup->signal_activate().connect(sigc::mem_fun(*this, &GtkView::on_new_group) );

    refXml->get_widget("menu_JoinGroup", menu_JoinGroup);
    menu_JoinGroup->signal_activate().connect(sigc::mem_fun(*this, &GtkView::on_join_group) );

    refXml->get_widget("menu_Quit", menu_Quit);
    menu_Quit->signal_activate().connect(sigc::mem_fun(*this, &GtkView::on_quit) );

    /* Tools menu's callbacks */

    refXml->get_widget("menu_SyncFiles", menu_SyncFiles);
    menu_SyncFiles->signal_activate().connect(sigc::mem_fun(*this, &GtkView::on_sync_files) );

    refXml->get_widget("menu_SyncContacts", menu_SyncContacts);
    menu_SyncContacts->signal_activate().connect(sigc::mem_fun(*this, &GtkView::on_sync_contacts) );

    /* Help menu's callbacks */
    refXml->get_widget("menu_About", menu_About);
    menu_About->signal_activate().connect(sigc::mem_fun(*this, &GtkView::on_about) );

    /* Initialise the main toolbar's buttons */
    Gtk::ToolButton* toolbar_AddFolder;
    Gtk::ToolButton* toolbar_AddMember;
    Gtk::ToolButton* toolbar_NewGroup;
    Gtk::ToolButton* toolbar_JoinGroup;
    Gtk::ToolButton* toolbar_SyncFiles;
    Gtk::ToolButton* toolbar_SyncContacts;

    /* Connect main toolbar's callback signals*/
    refXml->get_widget("toolbar_AddFolder", toolbar_AddFolder);
    toolbar_AddFolder->signal_clicked().connect(sigc::mem_fun(*this, &GtkView::on_click_add) );

    refXml->get_widget("toolbar_AddMember", toolbar_AddMember);
    toolbar_AddMember->signal_clicked().connect(sigc::mem_fun(*this, &GtkView::on_add_member) );

    /* Adding a new group */
    refXml->get_widget("toolbar_NewGroup", toolbar_NewGroup);
    toolbar_NewGroup->signal_clicked().connect(sigc::mem_fun(*this, &GtkView::on_new_group) );


    refXml->get_widget("toolbar_JoinGroup", toolbar_JoinGroup);
    toolbar_JoinGroup->signal_clicked().connect(sigc::mem_fun(*this, &GtkView::on_join_group) );

    refXml->get_widget("toolbar_SyncFiles", toolbar_SyncFiles);
    toolbar_SyncFiles->signal_clicked().connect(sigc::mem_fun(*this, &GtkView::on_sync_files) );

    refXml->get_widget("toolbar_SyncContacts", toolbar_SyncContacts);
    toolbar_SyncContacts->signal_clicked().connect(sigc::mem_fun(*this, &GtkView::on_sync_contacts) );

    /* Connect TreeView signals */
    //mTreeView->signal_row_expanded().connect(sigc::mem_fun(*this, &GtkView::on_treeview_row_expanded) );
    refTreeSelection->signal_changed().connect(sigc::mem_fun(*this, &GtkView::on_treeview_row_selected) );

    /* IconView signals */
    /* Activation downloads a file */
    mIconView->signal_item_activated().connect(sigc::mem_fun(*this, &GtkView::on_iconview_item_activated) );

    /* Selection updates info pane */
    //Gtk::IconView::SlotForeach sl = sigc::mem_fun(*this, &GtkView::on_iconview_selected_foreach );
    //mIconView->selected_foreach(sl);
    mIconView->signal_selection_changed().connect(sigc::mem_fun(*this, &GtkView::on_iconview_selected_foreach) );

    /* About dialog signals */
    dialog_About->signal_response().connect(sigc::mem_fun(*this, &GtkView::on_about_quit) );
    }
    else
    {
        cout << "quitting" << endl;
        on_quit();
    }

}

void GtkView::fillrow(Gtk::TreeModel::Row& row, file_tree::pre_order_iterator& it)
{
    // et on défini le contenu
    row[mColumns.name_col] = Glib::ustring(it->_name());
    row[mColumns.path_col] = Glib::ustring(it->_path());
    row[mColumns.host_col] = Glib::ustring(it->_owner()._address());
    row[mColumns.owner_col] = Glib::ustring(it->_owner()._nickname());

    if (it->isDir())
    {
        row[mColumns.type_col] = Glib::ustring("folder");
        row[mColumns.icon_col] = Gdk::Pixbuf::create_from_file("/usr/share/pixmaps/gnome-folder.png");
    }
    else
    {
        row[mColumns.type_col] = Glib::ustring("file");
        row[mColumns.icon_col] = Gdk::Pixbuf::create_from_file("/usr/share/pixmaps/gnome-file-c.png");
    }
}

void GtkView::fillTreeView( void )
{
    Gtk::TreeModel::Row row;

    file_tree::pre_order_iterator it;
    file_tree tr;
    unsigned int i, nChildren;

    mRefTreeModel->clear();

    tr = infobus->_commonFilesTree();

    it = tr.begin();
    // Boucle while qui pour chaque noeud de la racine, lance une recursion sur les noeuds inferieurs.
    while (it!=tr.end())
    {

        // debug
        cout << "filltreeview: " << it->_name() << " - " << it->_path() << endl;

        // on ajoute une ligne
        row = *(mRefTreeModel->append());
        // et on défini le contenu des noeuds de la racine
        fillrow(row, it);

        nChildren = tr.number_of_children(it);
        it++;

        // On lance une recursion sur les noeuds fils du noeud de la racine en cours.
        for (i=0; i<nChildren; i++)
        {
            // debug
            // cout << "filltreeview recursion entering: " << i << endl;

            fillTreeViewFrom(row, tr, it);
        }
    }
}

void GtkView::fillTreeViewFrom(Gtk::TreeModel::Row parentrow, const file_tree& tr, file_tree::pre_order_iterator& it)
{
    Gtk::TreeModel::Row childrow;
    unsigned int i, nChildren;

    nChildren = tr.number_of_children(it);

    // on ajoute une ligne
    childrow = *(mRefTreeModel->append(parentrow.children()));
    fillrow(childrow, it);

    ++it;
    // On relance la recursion sur les noeuds fils de ce noeud.
    for (i=0; i<nChildren; i++)
    {
        // debug
        //cout << "Childrow recursion: " << i << endl;

        fillTreeViewFrom(childrow, tr, it);
    }

}

Gtk::Window* GtkView::_mainwin(void)
{
    return mainWin;
}

int GtkView::login(int& argc, char**& argv)
{
    Gtk::Entry* entry_LoginUser;
    Gtk::Entry* entry_LoginHost;
    Gtk::Entry* entry_LoginPort;
    unsigned int portnum;
    // retrieves the port number from the command prompt if passed.
    if ( argc > 1 )
    {
        refXml->get_widget("entry_LoginPort", entry_LoginPort);
        entry_LoginPort->set_text(argv[1]);
    }

    int response_Login = dialog_Login->run();

    if (response_Login == Gtk::RESPONSE_OK)
    {
        // response debug
        cout << "ok clicked" << endl;

        refXml->get_widget("entry_LoginUser", entry_LoginUser);
        refXml->get_widget("entry_LoginHost", entry_LoginHost);
        refXml->get_widget("entry_LoginPort", entry_LoginPort);

        std::string usertext = std::string( entry_LoginUser->get_text() );
        std::string hosttext = std::string( entry_LoginHost->get_text() );
        std::string porttext = std::string( entry_LoginPort->get_text() );

        // debug entry
        cout << "port: " << porttext << " - " << "Arg number: " << argc << endl;

        portnum = atoi(porttext.c_str());
        infobus->start(usertext, hosttext, portnum);
        // debug
        // cout << data.groups->_name() << endl;

        dialog_Login->hide();
        return response_Login;
    }
    else
    {
        // response debug
        cout << "cancel clicked" << endl;
        dialog_Login->hide();
        return response_Login;
    }
}
